//
//  String+Tool.swift
//  huiAmusement
//
//  Created by Rowling on 2018/10/8.
//  Copyright © 2018年 Rowling. All rights reserved.
//

import Foundation
import UIKit

extension String : ZMCompatible {}
// MARK: - String类型的拓展
extension ZM where Base == String {
    /// 手机号正则
    func isPhoneNum()->Bool{
        let isPhone = match("^((13[0-9])|(14[0-9])|(15[0-9])|(16[0-9])|(17[0-9])|(18[0-9])|(19[0-9]))\\d{8}$")
        return isPhone
    }
    
    /// 邮箱验证
    func isEmail() -> Bool {
        let isEmail = match("^[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}$")
        return isEmail
    }
    
    /// 身份证正则
     func isIDCardNum()->Bool{
        return match("^(\\d{14}|\\d{17})(\\d|[X])$")
    }
    
    /// 匹配正则
    func match(_ regex:String) -> Bool {
        return NSPredicate(format: "SELF MATCHES %@", regex).evaluate(with: self.base)
    }
    
    /// 包含字母和数字
    func isLetterWithDigital() -> Bool {
        let numberRegex: NSPredicate = NSPredicate(format:"SELF MATCHES %@","^.*[0-9]+.*$")
        let letterRegex: NSPredicate = NSPredicate(format:"SELF MATCHES %@","^.*[A-Za-z]+.*$")
        if numberRegex.evaluate(with: base) && letterRegex.evaluate(with: base){
            return true
        }else{
            return false
        }
    }
    
    /// 筛选数字
    func filterNum() -> String {
        var result = ""
        for a in base {
            let regex = "^[0-9]*$"
            let subs = String(a)
            let ok = NSPredicate(format: "SELF MATCHES %@",regex).evaluate(with: subs)
            if ok {
                result.append(subs)
            }
        }
        return result
    }
    
    func isEmpty() -> Bool {
        return base.trimmingCharacters(in: [" "]).isEmpty
    }
    
    ///MD5加密
    /// - Returns: 加密后字符串
    func MD5() -> String {
        let str = base.cString(using: String.Encoding(rawValue: String.Encoding.utf8.rawValue))
        let strLen = CUnsignedInt(base.lengthOfBytes(using: String.Encoding(rawValue: String.Encoding.utf8.rawValue)))
        let digestLen = Int(CC_MD5_DIGEST_LENGTH)
        let result = UnsafeMutablePointer<UInt8>.allocate(capacity: 16)
        CC_MD5(str!, strLen, result)
        let hash = NSMutableString()
        for i in 0 ..< digestLen {
            hash.appendFormat("%02x", result[i])
        }
        free(result)
        return String(format: hash as String)
    }
    
    func xmToString(keep:Int) -> String {
        let d = NSDecimalNumber.init(string: base)
        let r = d.rounding(accordingToBehavior: ZMUtil.DecimalNumberHandler(roundingMode: .down, scale: Int16(keep)))
        return r.stringValue
    }
    
    /// 去掉空格
    func noWhitespace() -> String {
        let str = self.base as NSString
        let after = str.replacingOccurrences(of: " ", with: "")
        return after as String
    }

    /// 获取字符串长度
    var length: Int {return base.count}
        
    /// 获取某个下标的字符
    func character(at index: Int) -> Character {
        return self.base[self.base.index(self.base.startIndex, offsetBy: index)]
    }
        
    /// 从某个下标开始截取字符串
    func substring(from index: Int) -> String {
        if index > length {
           return ""
        }
        let range = self.base.index(self.base.startIndex, offsetBy: index) ..< self.base.index(self.base.endIndex, offsetBy: 0)
        let sub = self.base[range]
        return String(sub)
    }

    /// 从开始截取到某个下标
    func substring(to index: Int) -> String {
        if index > length {
            return base
        }
        let range = self.base.startIndex ..< self.base.index(self.base.startIndex, offsetBy: index)
        let sub = self.base[range]
        return String(sub)
    }
    
    // 转Int
    func hk_toInt() -> Int {
        return (base as NSString).integerValue
    }
    
    // 转Double
    func hk_toDouble() -> Double {
        return (base as NSString).doubleValue
    }
    
    // 转Float
    func hk_toFloat() -> Float {
        return (base as NSString).floatValue
    }
    
    /// 转Bool
    func hk_toBool() -> Bool {
        return (base as NSString).lowercased == "yes"
    }
    
    /// 小数位处理, 小数位全是0返回整数，小数超过2位返回2位
    func decimalPlaces() -> String {
        let arr = base.components(separatedBy: ".")
        if arr.last!.zm.hk_toInt() == 0 {
            return arr.first!
        } else if arr.count == 2 && arr.last!.count > 1 {
            return String(format: "%.2f", base.zm.hk_toDouble())
        } else {
            return base
        }
    }
    
    /// 汉字转拼音
    func toPinYin() -> String {
        let mutableString = NSMutableString(string: base)
        CFStringTransform(mutableString, nil, kCFStringTransformToLatin, false)
        CFStringTransform(mutableString, nil, kCFStringTransformStripDiacritics, false)
        let string = String(mutableString)
        return string.replacingOccurrences(of: " ", with: "")
    }
    
    /// 返回大写拼音首字母, 如果不是拼音，返回#
     func pinyinInitial(_ isHandelPolyphone:Bool = false) -> String {
        if base.count == 0 {return "#"}
        // 注意,这里一定要转换成可变字符串
        let mutableString = NSMutableString.init(string: base)
        // 将中文转换成带声调的拼音
        CFStringTransform(mutableString as CFMutableString, nil, kCFStringTransformToLatin, false)
        // 去掉声调
        let pinyinString = mutableString.folding(options: String.CompareOptions.diacriticInsensitive, locale: NSLocale.current)
        // 将拼音首字母装换成大写
        let strPinYin = isHandelPolyphone ? polyphoneStringHandle(nameString: base, pinyinString: pinyinString).uppercased() : pinyinString.uppercased()
        
        // 截取大写首字母
        let firstString = strPinYin.zm.substring(to: 1)
        // 判断姓名首位是否为大写字母
        let regexA = "^[A-Z]$"
        let predA = NSPredicate.init(format: "SELF MATCHES %@", regexA)
        return predA.evaluate(with: firstString) ? firstString : "#"
    }
    
    /// 多音字处理
    private func polyphoneStringHandle(nameString:String, pinyinString:String) -> String {
        if nameString.hasPrefix("长") {return "chang"}
        if nameString.hasPrefix("沈") {return "shen"}
        if nameString.hasPrefix("厦") {return "xia"}
        if nameString.hasPrefix("地") {return "di"}
        if nameString.hasPrefix("重") {return "chong"}
        return pinyinString;
    }
    
    /// 是否是银行卡号
    public func isBankCarNum()->Bool{
        let pattern1 = "[0-9]{12,24}"
        let ok = NSPredicate(format: "SELF MATCHES %@",pattern1).evaluate(with: base)
        return ok
    }
    
    /// 手机号中间4位替换为*
    func hidPhone(_ rang: NSRange = NSMakeRange(3,4)) -> String {
        guard base.zm.isPhoneNum() else {
            return base
        }
        return (base as NSString).replacingCharacters(in: rang, with: "****")
    }
    
    /// 替换为*
    func hideString(_ rang: NSRange) -> String {
        var newStr = ""
        for i in 0 ..< base.count {
            let c = base[i]
            if i < rang.location || i >= rang.location + rang.length {
                newStr.append(c)
            } else  {
                newStr.append("*")
            }
        }
        return newStr
    }
    
    
    
    func replaceStar(_ rang: NSRange = NSMakeRange(3,4)) -> String {
        var star = ""
        for _ in 0..<rang.length {
            star.append("*")
        }
        return (base as NSString).replacingCharacters(in: rang, with: star)
    }
    
    /// 银行卡号后部分替换为*
    func hideBankNum() -> String {
        guard base.zm.isBankCarNum() else {
            return base
        }
        return base.subString(location: 0, length: 4) + "********" + base.subString(location: base.count - 4, length: 4)
    }
    
    /// 银行卡号后部分替换为*
    func hideIdNum() -> String {
        guard base.zm.isIDCardNum() else {
            return base
        }
        return base.subString(location: 0, length: 6) + "********" + base.subString(location: base.count - 4, length: 4)
    }
    
    /// 16禁止字符串转颜色
    func hex() -> UIColor {
       return UIColor.zm.color(hexString: base)
    }
    
    /// 生成属性字符串
    func attributedStr(subString : String = "" , attrs : [NSAttributedString.Key : Any]) -> NSMutableAttributedString{
        let allStr = base
        let atr = NSMutableAttributedString(string: allStr)
        if subString.count > 0 {
           let nsVipStr = subString
           let range = (allStr as NSString).range(of: nsVipStr)
           atr.addAttributes(attrs, range: range)
        } else {
           atr.addAttributes(attrs, range: NSRange(location: 0, length: allStr.count))
        }
        return atr
    }
    
    /// 计算文字的宽高; width 文本框宽度，默认MAXFLOAT；height 文本框高度，默认MAXFLOAT；font 文本字体，默认系统12号
    func size(width: CGFloat = CGFloat(MAXFLOAT), height:CGFloat = CGFloat(MAXFLOAT), font: UIFont = UIFont.systemFont(ofSize: 12) , needDefaulHeight : Bool = true) -> CGSize {
        if !needDefaulHeight, base.count == 0 {return CGSize.zero}
        return (base as NSString).boundingRect(with: CGSize(width: width, height: height), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font:font], context: nil).size
    }
    
    /// 字符串转Date  默认yyyy-MM-dd
    func toDate(formate : String = "yyyy-MM-dd") -> Date? {
        let dateFormatter = DateFormatter.init()
        dateFormatter.locale = Locale.init(identifier: "zh_CN")
        dateFormatter.dateFormat = formate
        let date = dateFormatter.date(from: base)
        return date
    }
    
    /// 时间戳转对应字符串 默认yyyy-MM-dd
    func stampToString(formate : String = "yyyy-MM-dd") -> String {
        guard var stamp = TimeInterval(self.base) else {return self.base}
        stamp = base.count == 10 ? stamp : stamp / 1000
        let theDate = Date(timeIntervalSince1970: stamp)
        let fo = DateFormatter()
        fo.dateFormat = formate
        fo.locale = Locale.init(identifier: "en_US_POSIX")
        fo.calendar = Calendar.init(identifier: Calendar.Identifier.gregorian)
        return fo.string(from: theDate)
    }
    
    /// 时间字符串转时间戳 默认 yyyy-MM-dd HH:mm:ss
    func stringToTimeStamp(formate: String = "yyyy-MM-dd HH:mm:ss") -> String {
        let dfmatter = DateFormatter()
        dfmatter.dateFormat = formate
        dfmatter.locale = Locale.init(identifier: "en_US_POSIX")
        dfmatter.calendar = Calendar.init(identifier: Calendar.Identifier.gregorian)
        guard let date = dfmatter.date(from: base) else {return ""}
        let dateStamp: TimeInterval = date.timeIntervalSince1970
        let dateSt:Int = Int(dateStamp)
        return String(dateSt)
    }
    
    /// 时间字符串转对应字符串
    func stringToString(formate: String = "yyyy-MM-dd HH:mm:ss", toFormate: String = "yyyy-MM-dd HH:mm:ss") -> String {
        let timeStamp = base.zm.stringToTimeStamp(formate: formate)
        return timeStamp.zm.stampToString(formate: toFormate)
    }
    
    /// 时间字符串转时间戳
    func place(_ str : String) -> String {
        if base.count == 0 {
            return str
        }
        return base
    }
    
    /// 拨打电话
    func makeACall() {
        let phoneStr = "telprompt://\(base)"
        UIApplication.shared.open(URL(string: phoneStr)!)
    }
    
    /// 是否匹配该正则表达式
    func match(regex : String) -> Bool {
        let p = NSPredicate(format: "SELF MATCHES %@", regex)
        return p.evaluate(with: base)
    }
    
    func subString(regex : String) -> (ranges : [NSRange],strings : [String]) {
        var ranges = [NSRange]()
        var strings = [String]()
        do {
            let nsStr = base as NSString
            let reExp = try NSRegularExpression(pattern: regex, options: NSRegularExpression.Options.caseInsensitive)
            let results = reExp.matches(in: base, options: NSRegularExpression.MatchingOptions.reportProgress, range: NSMakeRange(0, nsStr.length))
            for rs in results {
                ranges.append(rs.range)
                let r = nsStr.substring(with: rs.range)
                strings.append(r as String)
            }
        }
        catch {}
        return (ranges,strings)
    }
    
    func htmlToString() -> String {
//        style='background-color: #f00;'
        return String(format: "<html><head><style>img{width:100% !important;height:auto}</style></head><body><p>%@</p></body></html>", base)
    }
    
    func htmlToAttributedString(_ width: CGFloat = SCREEN_W) -> NSAttributedString {
        let str = String(format: "<html><head><style>img{width:%f !important;height:auto}</style></head><body>%@</body></html>", width, base)
        do {
            if let data = str.data(using: String.Encoding.unicode, allowLossyConversion: true) {
                let attStr = try NSAttributedString.init(data: data, options: [NSAttributedString.DocumentReadingOptionKey.documentType : NSAttributedString.DocumentType.html,], documentAttributes: nil)
                return attStr
            }
        } catch {
            return NSAttributedString(string: base)
        }
        return NSAttributedString(string: base)
    }
    
    func htmlBigSizeString() -> String {
        print(base)
//        return base
        
        return """
        <html lang="en"><head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=2.0,user-scalable=no">
            <style>
            img {
                width: 100%
            }
            span {
                white-space: pre-wrap !important;
            }
            a {
                word-break: break-all !important;
            }
            </style>
        </head>
        <body class="white-space: pre-wrap !important;">
                \(base)
        </body></html>
        """
        
//        return "<style></style><div style=\"font-size: 24px;\"></div>"
    }
    
    func toDictionary() ->[String : Any]?{
        let jsonData:Data = base.data(using: .utf8)!
        var dict : Any?
        do {
            dict = try JSONSerialization.jsonObject(with: jsonData, options: .mutableContainers)
        }
        catch {
            
        }
        if dict != nil {
            return dict as? [String : Any]
        }
        return nil
    }
    
    /// json字符串 转 字符串数组
    func toArray() -> [String]? {
        let jsonData:Data = base.data(using: .utf8)!
        var arr : Any?
        do {
            arr = try JSONSerialization.jsonObject(with: jsonData, options: .mutableContainers)
        }
        catch {
            
        }
        if arr != nil {
            return arr as? [String]
        }
        return nil
    }
    
    /// json字符串 转 字符串数组
    func toModelArray<T: HandyJSON>(_ type: T.Type) -> [T]? {
        let jsonData:Data = base.data(using: .utf8)!
        var arr : [Any]?
        do {
            arr = try JSONSerialization.jsonObject(with: jsonData, options: .mutableContainers) as? [Any]
        }
        catch {
            
        }
        if let arr = arr {
            let modelArr = arr.compactMap { val in
                if let str = val as? String {
                    if let model = JSONDeserializer<T>.deserializeFrom(json: str) {
                        return model
                    }
                    return nil
                } else if let info = val as? [String: Any] {
                    if let model = JSONDeserializer<T>.deserializeFrom(dict: info) {
                        return model
                    }
                    return nil
                } else {
                    return nil
                }
            }
            return modelArr
        }
        return nil
    }
    
    func getCharacterCount() -> Int {
        let enc = CFStringConvertEncodingToNSStringEncoding(CFStringEncoding(CFStringEncodings.GB_18030_2000.rawValue))
        let data = (base as NSString).data(using: enc)! as NSData
        return data.length
    }
    
    func aliImg(h:Int) -> String {
        if base.contains(".oss") && !base.contains("?x-oss-process=image") {
            return base + "?x-oss-process=image/resize,h_\(h),m_lfit"
        }
        else {
            return base
        }
    }
    
    func append(str : String,font : UIFont? = nil,color : UIColor? = nil, attri : [String : Any]? = nil) -> NSMutableAttributedString {
        let at =  NSMutableAttributedString(string: base).zm.append(str: str, font: font, color: color, attri: attri)
        return at
    }
}


extension String {
    /// 获取指定长度的字符
    ///
    /// - Parameters:
    ///   - location: 起始位置
    ///   - length: 所需长度
    /// - Returns: 截取后的内容
    func subString(location: Int, length: Int) -> String {
        let fromIndex = self.index(startIndex, offsetBy: location)
        let toIndex   = self.index(fromIndex, offsetBy: length)
        let subString = self[fromIndex..<toIndex]
        return String(subString)
    }
}
